//
//  SGGraphDataProvider.m
//  SpringGraph Test
//
//  Created by Jack Herrington on 5/30/10.
//  Copyright 2010 Myself. All rights reserved.
//

#import "SGGraphDataProvider.h"

#import "FLAbstractEdge.h"
#import "SGSpringGraph.h"

@interface SGGraphDataProvider (PrivateMethods) 

- (FLNode *)makeGraphNode:(UIView *)item;
- (void)update;
- (bool)hasNode:(NSInteger)iid;
- (UIView *)findView:(NSInteger)itemId;

@end

@implementation SGGraphDataProvider

- (SGGraphDataProvider *)initWithGraph:(id<NSObject,SGGraphDataDelegate>)graph {
	self = [super init];
	if ( self ) {
		_graphNodes = [[NSMutableDictionary alloc] init];
		_viewsById = [[NSMutableDictionary alloc] init];
		_nodes = [[NSMutableArray alloc] init];

		_edges = [[NSMutableArray alloc] init];
		_edgesById = [[NSMutableDictionary alloc] init];
		
		dataDelegate = [graph retain];
	}
	return self;
}

- (void)dealloc {
	[_edgesById	release];
	[dataDelegate release];
	[_graphNodes release];
	[_nodes release];
	[_edges release];
	[super dealloc];
}

- (NSArray *)edges {
	return [[_edges copy] autorelease];
}

- (void)forAllNodes:(id<NSObject, FLIterator>)iterator {
	for (FLNode *node in _nodes) {
		[iterator forEachNode:node itemId:node.itemId];
	}
}

- (void)forAllEdges:(id<NSObject, FLIterator>)iterator {
	for (FLAbstractEdge *edge in _edges) {
		[iterator forEachEdge:edge];
	}
}

- (void)forAllNodePairs:(id<NSObject, FLIterator>)iterator {
	for (FLNode *node1 in _nodes) {
		for (FLNode *node2 in _nodes) {
			if ( node1 != node2 )
				[iterator forEachNodePair:node1 b:node2];
		}
	}
}

- (void)update {
	NSMutableArray *newEdges = [[[NSMutableArray alloc] init] autorelease];
	NSMutableDictionary *done = [[[NSMutableDictionary alloc] init] autorelease];
	for( NSNumber *itemID in [_edgesById allKeys] ) {
		[done setObject:[NSNumber numberWithInt:1] forKey:itemID];
		NSMutableDictionary *friends = [_edgesById objectForKey:itemID];
		for( NSNumber *friendId in [friends allKeys] ) {
			if ( [done objectForKey:friendId] == nil ) {
				[newEdges addObject:[NSArray arrayWithObjects:itemID, friendId, nil]];
			}
		}
	}
	
	NSMutableArray *oldNodes = _nodes;
	
	_nodes = [[NSMutableArray alloc] init];

	NSDictionary *newItems = self.nodes;
	for( UIView *item in [newItems allValues] ) {
		[_nodes addObject:[self makeGraphNode:item]];
	}
	
	if ( oldNodes != nil ) {
		for( FLNode *oldNode in oldNodes ) {
			if ( ![self hasNode:oldNode.itemId] ) {
				UIView *view = [self findView:oldNode.itemId];
				if ( view.superview != nil ) {
					[_graphNodes removeObjectForKey:[NSNumber numberWithInt:oldNode.itemId]];
				}
			}
		}
	}
	
	[oldNodes release];
	
	[_edges release];
	_edges = [[NSMutableArray alloc] init];
	
	for ( NSArray *edge in newEdges ) {
		FLAbstractEdge *newEdge = [[FLAbstractEdge alloc] init];
		
		NSNumber *item1 = [edge objectAtIndex:0];
		NSNumber *item2 = [edge objectAtIndex:1];
		
		newEdge.from = [_graphNodes objectForKey:item1];
		newEdge.to = [_graphNodes objectForKey:item2];

		[_edges addObject:newEdge];
	}
	
	[dataDelegate refresh];
}

- (FLNode *)findNode:(UIView *)view {
	for( NSNumber *nodeId in _nodes ) {
		if ( [_viewsById objectForKey:nodeId] == view )
			return [_viewsById objectForKey:nodeId];
	}
	return nil;
}

- (float)repulsionFactor {
	return dataDelegate.repulsionFactor;
}

- (float)defaultRepulsionFactor {
	return dataDelegate.defaultRepulsionFactor;
}

- (FLNode *)makeGraphNode:(UIView *)item {
	if ( [_graphNodes objectForKey:[NSNumber numberWithInt:item.tag]] == nil )
	{
		FLNode *newNode = [[FLNode alloc] init];
		newNode.itemId = item.tag;
		[_graphNodes setObject:newNode forKey:[NSNumber numberWithInt:item.tag]];
	}
	return [_graphNodes objectForKey:[NSNumber numberWithInt:item.tag]];
}

- (NSDictionary *)nodes {
	return [[_viewsById copy] autorelease];
}

- (bool)hasNode:(NSInteger)iid {
	return [_viewsById objectForKey:[NSNumber numberWithInt:iid]] != nil;
}

- (void)add:(UIView *)item {
	[_viewsById setObject:item forKey:[NSNumber numberWithInt:item.tag]];
	[_edgesById setObject:[[NSMutableDictionary alloc] init] forKey:[NSNumber numberWithInt:item.tag]];
	[self update];
}

- (SGEdgeData *)link:(UIView *)item to:(UIView *)to {
	SGEdgeData *edgeData = [[SGEdgeData alloc] init];
	
	NSMutableDictionary *friends = [_edgesById objectForKey:[NSNumber numberWithInt:item.tag]];
	[friends setObject:edgeData forKey:[NSNumber numberWithInt:to.tag]];
	
	friends = [_edgesById objectForKey:[NSNumber numberWithInt:to.tag]];
	[friends setObject:edgeData forKey:[NSNumber numberWithInt:item.tag]];
	
	[self update];
	
	return edgeData;
}

- (SGEdgeData *)getLinkData:(UIView	*)item to:(UIView *)to {
	NSMutableDictionary *friends = [_edgesById objectForKey:[NSNumber numberWithInt:item.tag]];
	if ( friends == nil )
		return nil;
	return [friends objectForKey:[NSNumber numberWithInt:to.tag]];
}

- (void)remove:(UIView *)item {
	[_edgesById removeObjectForKey:[NSNumber numberWithInt:item.tag]];
	[_viewsById removeObjectForKey:[NSNumber numberWithInt:item.tag]];
	for( NSMutableDictionary *friends in [_edgesById allValues]) {
		[friends removeObjectForKey:[NSNumber numberWithInt:item.tag]];
	}

	[self update];
}

- (void)unlink:(UIView *)item to:(UIView *)to {
	NSMutableDictionary *friends = [_edgesById objectForKey:[NSNumber numberWithInt:item.tag]];
	[friends removeObjectForKey:[NSNumber numberWithInt:to.tag]];
	
	friends = [_edgesById objectForKey:[NSNumber numberWithInt:to.tag]];
	[friends removeObjectForKey:[NSNumber numberWithInt:item.tag]];

	[self update];
}

- (CGPoint)getPosition:(NSInteger)nodeId {
	UIView *view = [self findView:nodeId];
	return CGPointMake(view.frame.origin.x, view.frame.origin.y);
}

- (float)getRepulsion:(NSInteger)nodeId {
	UIView *view = [self findView:nodeId];
	float result = ( view.frame.size.height + view.frame.size.width ) * self.repulsionFactor;
	return ( result > 0 ) ? result : self.defaultRepulsionFactor;
}

- (void)setPosition:(NSInteger)nodeId position:(CGPoint)position {
	UIView *view = [self findView:nodeId];
	if ( position.y != view.frame.origin.y || position.x != view.frame.origin.x ) {
		[dataDelegate moveView:view position:position];
	}
}

- (float)getEdgeLength:(FLNode *)from to:(FLNode *)to {
	UIView *fv = [self findView:from.itemId];
	UIView *tv = [self findView:to.itemId];
	
	float result = ( fv.frame.size.width + fv.frame.size.height + tv.frame.size.width + tv.frame.size.height ) / 4;
	return ( result > 0 ) ? result : 50;
}

- (UIView *)findView:(NSInteger)itemId {
	return [_viewsById objectForKey:[NSNumber numberWithInt:itemId]];
}

@end
